// Package object 将结构体切片封装为对象，提供线程安全的操作方法
package object

import (
	"reflect"
	"sort"
	"sync"
)

// structSliceLocker 接口，包含锁的基本操作方法
type structSliceLocker interface {
	Lock()    // 加锁操作
	Unlock()  // 解锁操作
	RLock()   // 读锁操作
	RUnlock() // 读解锁操作
}

// structSliceNotLocker 实现structSliceLocker接口的方法，但方法为空
type structSliceNotLocker struct{}

func (structSliceNotLocker) Lock()    {} // 实现加锁操作，无实际操作
func (structSliceNotLocker) Unlock()  {} // 实现解锁操作，无实际操作
func (structSliceNotLocker) RLock()   {} // 实现读锁操作，无实际操作
func (structSliceNotLocker) RUnlock() {} // 实现读解锁操作，无实际操作

// structSliceSafeLocker 内嵌sync.RWMutex来保证线程安全
type structSliceSafeLocker struct {
	locker sync.RWMutex // 声明一个读写互斥锁
}

func (l *structSliceSafeLocker) Lock()    { l.locker.Lock() }    // 实现加锁操作
func (l *structSliceSafeLocker) Unlock()  { l.locker.Unlock() }  // 实现解锁操作
func (l *structSliceSafeLocker) RLock()   { l.locker.RLock() }   // 实现读锁操作
func (l *structSliceSafeLocker) RUnlock() { l.locker.RUnlock() } // 实现读解锁操作

// StructSlice 结构体，用于存储字符串切片，并通过locker来控制线程安全
type StructSlice[T any] struct {
	Values []T               // 存储实际的字符串切片数据
	locker structSliceLocker // 使用structSliceLocker接口实现锁定机制
}

// NewStructSlice 函数创建StructSlice实例，可以选择是否线程安全
func NewStructSlice[T any](values []T, threadSafe bool) *StructSlice[T] {
	var dummy T
	if reflect.TypeOf(dummy).Kind() != reflect.Struct {
		panic("T must be a struct")
	}
	s := &StructSlice[T]{Values: values} // 创建StructSlice实例
	if threadSafe {
		s.locker = &structSliceSafeLocker{} // 如果需要线程安全，则设置locker为StructSliceSafeLocker
	} else {
		s.locker = structSliceNotLocker{} // 否则设置为不进行任何操作的locker
	}
	return s // 返回创建的StructSlice实例
}

// Set 方法设置切片的值
func (s *StructSlice[T]) Set(values []T) {
	s.locker.Lock()         // 加锁
	defer s.locker.Unlock() // 方法最后解锁
	s.Values = values       // 设置Values为传入的切片
}

// Get 方法获取切片的值
func (s *StructSlice[T]) Get() []T {
	s.locker.RLock()         // 读锁
	defer s.locker.RUnlock() // 方法最后解锁
	return s.Values          // 返回Values切片
}

// Clean 方法清空切片
func (s *StructSlice[T]) Clean() {
	s.locker.Lock()         // 加锁
	defer s.locker.Unlock() // 方法最后解锁
	s.Values = nil          // 设置Values为nil
}

// Size 方法获取切片的大小
func (s *StructSlice[T]) Size() int {
	s.locker.RLock()         // 读锁
	defer s.locker.RUnlock() // 方法最后解锁
	return len(s.Values)     // 返回Values切片的长度
}

// Clone 方法克隆切片
func (s *StructSlice[T]) Clone(threadSafe bool) *StructSlice[T] {
	s.locker.RLock()                         // 读锁
	defer s.locker.RUnlock()                 // 方法最后解锁
	clone := make([]T, len(s.Values))        // 创建一个与当前Values相同长度的切片
	copy(clone, s.Values)                    // 复制当前Values的元素到新切片
	return NewStructSlice(clone, threadSafe) // 使用新切片和threadSafe参数创建新的StructSlice实例，并返回
}

// Add 方法向切片中添加一个元素
func (s *StructSlice[T]) Add(item T) {
	s.locker.Lock()         // 加锁
	defer s.locker.Unlock() // 方法最后解锁
	// 检查元素是否存在
	for _, v := range s.Values {
		if reflect.DeepEqual(v, item) {
			return
		}
	}
	s.Values = append(s.Values, item) // 将元素添加到Values切片的末尾
}

// RemoveAtIndex 方法移除指定索引的元素
func (s *StructSlice[T]) RemoveAtIndex(index int, allowChangeOrder bool) {
	s.locker.Lock()         // 加锁
	defer s.locker.Unlock() // 方法最后解锁
	if allowChangeOrder {
		s.Values[index] = s.Values[len(s.Values)-1] // 如果允许改变顺序，将最后一个元素移动到待删除元素的位置
		s.Values = s.Values[:len(s.Values)-1]       // 缩减切片大小，移除最后一个元素
	} else {
		s.Values = append(s.Values[:index], s.Values[index+1:]...) // 不允许改变顺序，直接移除元素
	}
}

// RemoveAtIndices 方法根据一组索引移除多个元素
func (s *StructSlice[T]) RemoveAtIndices(indices []int, allowChangeOrder bool) {
	if allowChangeOrder {
		toBeRemoved := make(map[int]bool) // 创建一个map来标记待删除元素
		for _, index := range indices {
			toBeRemoved[index] = true // 标记待删除元素
		}
		s.locker.Lock()           // 加锁
		newValues := s.Values[:0] // 创建新的切片，用于存储未被删除的元素
		for i, value := range s.Values {
			if !toBeRemoved[i] {
				newValues = append(newValues, value) // 如果当前索引不在待删除map中，则将元素添加到新切片中
			}
		}
		s.Values = newValues // 更新Values为没有被删除元素的新切片
		s.locker.Unlock()    // 解锁
	} else {
		sort.Sort(sort.Reverse(sort.IntSlice(indices))) // 如果不允许改变顺序，先对索引进行降序排序
		for _, index := range indices {
			s.RemoveAtIndex(index, false) // 逐个索引移除元素
		}
	}
}
